﻿//========================================================= 
/**@file LC_FileCipherFactoryCmdDriver.h
 * @brief 基于文件的密钥器工厂
 * 
 * @date 2017-10-20   22:44:09
 * @author Zhyioo 
 * @version 1.0
 */ 
//--------------------------------------------------------- 
#ifndef _LIBZHOUYB_LC_FILECIPHERFACTORYCMDDRIVER_H_
#define _LIBZHOUYB_LC_FILECIPHERFACTORYCMDDRIVER_H_
//--------------------------------------------------------- 
#include "../CommonCmdDriver.h"

#include "LC_CipherCmdDriver.h"

#include "../../pinpad/FileVirtualCipher.h"
using zhou_yb::application::pinpad::FileVirtualCipher;

#include "../../lc/inc/LC_EncryptProvider.h"
using zhou_yb::application::lc::Binary_Provider;
using zhou_yb::application::lc::Padding_Provider;

#include "../../../extension/security/SM4_Provider.h"
using zhou_yb::extension::security::SM4_Provider;

#include "../../../extension/security/PBOC_Provider.h"
using zhou_yb::extension::security::PBOC_Provider;
//--------------------------------------------------------- 
namespace zhou_yb {
namespace application {
namespace driver {
//--------------------------------------------------------- 
/**
 * @brief 支持8/16/24字节的DES密钥算法
 * @date 2017-10-20 22:54
 */
class DesAutoProvider : public ISecurityAlgorithm, public RefObject
{
protected:
    ByteBuilder _key;
public:
    inline void Init(const ByteArray& key_8_16_24)
    {
        _key = key_8_16_24;
    }
    /// 加密 
    virtual bool Encrypt(const ByteArray& data, ByteBuilder& dst)
    {
        PBOC_Provider::Encrypt(_key, data, dst);
        return true;
    }
    /// 解密 
    virtual bool Decrypt(const ByteArray& data, ByteBuilder& dst)
    {
        PBOC_Provider::Decrypt(_key, data, dst);
        return true;
    }
};
//--------------------------------------------------------- 
/**
 * @brief 使用软加密方式的通信密钥工厂
 * @date 2017-10-21 09:51
 */
class LC_FileCipherFactoryCmdDriver : public CommonCmdDriver, public ICipherFactory
{
protected:
    Ref<ICipherFactory> _refFactory;
    uint _mkIndex;
    Ref<FileVirtualCipher> _refCipher;
    FileVirtualCipher _cipher;

    Binary_Provider _binary;
    Padding_Provider<DesAutoProvider, 16> _des;
    Padding_Provider<SM4_Provider, 16> _sm4;
    /// 获取指定的工作密钥
    Ref<ISecurityAlgorithm> _InitWK(uint wkIndex, const ByteArray& wk)
    {
        uint alg = wkIndex & 0xF0;
        switch(alg)
        {
        case 0x00:
            return _binary;
        case 0x10:
            _des.Provider.Init(wk);
            return _des;
        case 0x20:
            _sm4.Provider.Init(wk);
            return _sm4;
        }
        return Ref<ISecurityAlgorithm>();
    }
    /// 获取指定的通信加密器
    Ref<ISecurityAlgorithm> _CreateWK(uint mkIndex, uint wkIndex)
    {
        ByteBuilder wk(16);
        if(wkIndex >= 0x10 && wkIndex <= 0x2F)
        {
            if(!_cipher.GetWK(mkIndex, wkIndex, wk))
                return Ref<ISecurityAlgorithm>();
        }
        return _InitWK(wkIndex, wk);
    }
public:
    //----------------------------------------------------- 
    LC_FileCipherFactoryCmdDriver() : CommonCmdDriver()
    {
        _mkIndex = 0;
        _refFactory = (*this);
        _refCipher = _cipher;

        // 预初始化明文加密
        const byte MK[16] = { 0 };
        ByteArray KEY_VAL(MK, SizeOfArray(MK));
        _cipher.DownloadMK(_mkIndex, KEY_VAL);
        _cipher.DownloadWK(_mkIndex, 0, KEY_VAL);

        _RegisteCMD(LC_FileCipherFactoryCmdDriver, LoadKEY);
        _RegisteCMD(LC_FileCipherFactoryCmdDriver, RandomKEY);
        _RegisteCMD(LC_FileCipherFactoryCmdDriver, SaveKEY);
        _RegisteCMD(LC_FileCipherFactoryCmdDriver, ToKEY);
        _RegisteCMD(LC_FileCipherFactoryCmdDriver, ActiveMK);
        _RegisteCMD(LC_FileCipherFactoryCmdDriver, DownloadKEY);

        _RegisteExceptCMD(LC_FileCipherFactoryCmdDriver);
        _RegisteInterfaceCMD(LC_FileCipherFactoryCmdDriver, FileVirtualCipher);
        _RegisteInterfaceCMD(LC_FileCipherFactoryCmdDriver, ICipherFactory);
    }
    //----------------------------------------------------- 
    LC_CMD_EXCEPT()
    {
        EXCEPT_CMD(ActiveMK);
        return true;
    }
    LC_CMD_INTERFACE_GETTER(FileVirtualCipher, _refCipher);
    LC_CMD_INTERFACE_GETTER(ICipherFactory, _refFactory);
    //----------------------------------------------------- 
    virtual bool Create(Ref<ISecurityAlgorithm>& obj, const char* sArg)
    {
        byte wkIndex = ArgConvert::FromString<byte>(sArg);
        Ref<ISecurityAlgorithm> alg = _CreateWK(_mkIndex, wkIndex);
        if(alg.IsNull())
            return false;
        obj = alg;
        return true;
    }
    virtual bool IsValid(const Ref<ISecurityAlgorithm>& obj)
    {
        return obj.IsNull();
    }
    virtual void Dispose(Ref<ISecurityAlgorithm>& obj)
    {
        obj.Free();
    }
    //----------------------------------------------------- 
    /**
     * @brief 从指定的路径的密钥文件中加载密钥设置
     * @date 2017-10-22 10:21
     * 
     * @param [in] Path : string 需要加载的密钥配置文件
     * @param [in] MkIndex : uint [default:0] 需要使用的主密钥配置
     */
    LC_CMD_METHOD(LoadKEY)
    {
        string path = arg["Path"].To<string>();
        if(!_cipher.Load(path.c_str()))
            return false;
        uint mkIndex = arg["MkIndex"].To<uint>(0);
        _mkIndex = mkIndex;
        ByteBuilder mk(8);
        // 检测密钥是否存在
        if(!_cipher.GetMK(_mkIndex, mk))
        {
            _logErr(DeviceError::ArgRangeErr, "主密钥不存在");
            return false;
        }
        return true;
    }
    /**
     * @brief 随机产生一组密钥
     * @date 2017-11-21 09:25
     *
     * @param [in] MkIndex : uint [default:Null] 需要生成的主密钥序号(Null表示使用当前)
     * @param [in] MK : hex [default:Null] 需要下载的主密钥
     *
     * @param [in] WkIndex : byte [default:Null] 需要产生的工作密钥索引
     * @warning 如有WkIndex参数则忽略MIN和MAX参数
     *
     * @param [in] MIN : byte [default:0x00] 最小的密钥范围
     * @param [in] MAX : byte [default:0xFF] 最大的密钥范围
     *
     * @retval Count : size_t 下载的密钥数
     */
    LC_CMD_METHOD(RandomKEY)
    {
        const uint KEY_LENGTH = 16;

        uint mkIndex = arg["MkIndex"].To<uint>(_mkIndex);
        string sMk;
        ByteBuilder mk(16);
        if(arg.Get("MK", sMk))
        {
            DevCommand::FromAscii(sMk.c_str(), mk);
            ASSERT_FuncErrInfo(mk.GetLength() == KEY_LENGTH, DeviceError::ArgLengthErr, "主密钥长度错误");
            ASSERT_FuncErrInfo(_cipher.DownloadMK(mkIndex, mk), DeviceError::OperatorErr, "下载主密钥失败");
        }
        string sWkIndex;
        byte minIndex = 0x00;
        byte maxIndex = 0x00;
        if(arg.Get("WkIndex", sWkIndex))
        {
            minIndex = ArgConvert::FromString<byte>(sWkIndex);
            maxIndex = minIndex;
        }
        else
        {
            minIndex = arg["MIN"].To<byte>(0x00);
            maxIndex = arg["MAX"].To<byte>(0xFF);
        }
        size_t count = 0;
        for(uint i = minIndex;i <= maxIndex;++i)
        {
            mk.Clear();
            ByteConvert::Random(mk, KEY_LENGTH);
            ASSERT_FuncErrInfo(_cipher.DownloadWK(mkIndex, i, mk), DeviceError::OperatorErr, "下载工作密钥失败");
            ++count;
        }
        rlt.Put("Count", ArgConvert::ToString(count));
        return true;
    }
    /**
     * @brief 保存密钥配置文件
     * @date 2017-10-22 10:26
     * 
     * @param [in] Path : string [default:Null] 需要保存的新路径(Null,或""表示保存到原文件中)
     */
    LC_CMD_METHOD(SaveKEY)
    {
        string path = arg["Path"].To<string>();
        if(path.length() > 0)
            return _cipher.Save(path.c_str());
        return _cipher.Save();
    }
    /**
     * @brief 导出密钥Json数据
     * @date 2017-10-22 10:29:51
     *
     * @retval KEY : string 导出的Json格式密钥数据
     */
    LC_CMD_METHOD(ToKEY)
    {
        ByteBuilder sJson(32);
        _cipher.ToJSON(sJson);
        rlt.Put("KEY", sJson.GetString());
        return true;
    }
    /**
     * @brief 激活当前使用的主密钥序号
     * @date 2017-10-22 10:21
     * 
     * @param [in] MkIndex : uint [default:0] 需要激活的主密钥序号
     * 
     * @retval MkIndex : uint 上次使用的主密钥序号
     */
    LC_CMD_METHOD(ActiveMK)
    {
        uint mkIndex = arg["MkIndex"].To<uint>(0);
        rlt.Put("MkIndex", ArgConvert::ToString(_mkIndex));
        _mkIndex = mkIndex;
        return true;
    }
    /**
     * @brief 下载密钥
     * @date 2017-10-22 10:33:54
     * 
     * @param [in] MkIndex : uint 需要下载的密钥序号
     * @warning 主密钥只支持明文下载
     * 
     * @param [in] WkIndex : uint [default:Null] 需要下载的工作密钥序号(没有则表示下载主密钥)
     * @param [in] Key : hex 需要下载的密钥数据
     * @param [in] IsEncrypted : bool [default:false] 是否为密文数据
     * @param [in] KCV : hex [default:Null] 密钥的KCV
     *
     * @retval KCV : hex 密钥的KCV
     */
    LC_CMD_METHOD(DownloadKEY)
    {
        string sIndex;
        ASSERT_FuncErrInfo(arg.Get("MkIndex", sIndex), DeviceError::ArgIsNullErr, "缺少参数[MkIndex]");
        
        string sKey;
        ASSERT_FuncErrInfo(arg.Get("Key", sKey), DeviceError::ArgIsNullErr, "缺少参数[Key]");

        ByteBuilder key(16);
        DevCommand::FromAscii(sKey.c_str(), key);
        ASSERT_FuncErrInfo(!key.IsEmpty(), DeviceError::ArgFormatErr, "密钥数据为空");
        
        uint mkIndex = ArgConvert::FromString<uint>(sIndex);
        if(!arg.Get("WkIndex", sIndex))
        {
            // 下载主密钥
            return _cipher.DownloadMK(mkIndex, key);
        }
        // 下载工作密钥
        uint wkIndex = ArgConvert::FromString<uint>(sIndex);
        // 密文模式
        if(arg["IsEncrypted"].To<bool>(false))
        {
            ByteBuilder mk(16);
            ByteBuilder tmp(16);
            ASSERT_FuncErrInfo(_cipher.GetMK(mkIndex, mk), DeviceError::ArgErr, "解密主密钥不存在");
            Ref<ISecurityAlgorithm> alg = _InitWK(wkIndex, mk);
            ASSERT_FuncErrInfo(!alg.IsNull(), DeviceError::ArgRangeErr, "密钥不存在");
            alg->Decrypt(key, tmp);
            key.Swap(tmp);
            tmp.Clear();
            // 计算KCV
            const byte KCV_VAL[16] = { 0 };
            ByteBuilder kcv(8);
            alg->Encrypt(ByteArray(KCV_VAL, SizeOfArray(KCV_VAL)), kcv);
            ByteConvert::ToAscii(kcv, tmp);
            rlt.Put("KCV", tmp.GetString());

            string sKcv = arg["KCV"].To<string>();
            tmp.Clear();
            DevCommand::FromAscii(sKcv.c_str(), tmp);
            ASSERT_FuncErrInfo(StringConvert::StartWith(kcv, tmp), DeviceError::DevVerifyErr, "KCV校验失败");
        }
        return _cipher.DownloadWK(mkIndex, wkIndex, key);
    }
    //----------------------------------------------------- 
};
//--------------------------------------------------------- 
} // nemespace driver
} // namespace application
} // namespace zhou_yb
//--------------------------------------------------------- 
#endif // _LIBZHOUYB_LC_FILECIPHERFACTORYCMDDRIVER_H_
//========================================================= 